/*:
**     mesh.cc 
*/

#include "a48.h"
#include <map>

using namespace A48;


Mesh::Mesh()
{}


Mesh::~Mesh()
{
  for (VertexIter p = vc_.begin(); p != vc_.end(); p++)
    delete *p;
  vc_.clear();
  for (EdgeIter e = ec_.begin(); e != ec_.end(); e++)
    delete *e;
  ec_.clear();
  for (FaceIter f = fc_.begin(); f != fc_.end(); f++)
    delete *f;
  fc_.clear();
  for (PatchIter p = pc_.begin(); p != pc_.end(); p++)
    delete *p;
  pc_.clear();
}

void Mesh::delete_patches()
{
  for (PatchIter p = pc_.begin(); p != pc_.end(); p++)
    delete *p;
  pc_.clear();
}

Patch* Mesh::add_patch()
{
  Patch *p = new Patch();

  p->index = pc_.size();

  add_patch(p);
  return p;
}

Patch* Mesh::add_patch(int *i, int size, FaceMap* faces, int camera_index, float *box)
{
  Patch *p = new Patch();

  p->camera_index = camera_index;

  p->box3DMinX = box[0];
  p->box3DMinY = box[1];
  p->box3DMinZ = box[2];
  p->box3DMaxX = box[3];
  p->box3DMaxY = box[4];
  p->box3DMaxZ = box[5];

  p->box2DImgMinX = box[6];
  p->box2DImgMinY = box[7];
  p->box2DImgMaxX = box[8];
  p->box2DImgMaxY = box[9];

  p->box2DTextMinX = box[10];
  p->box2DTextMinY = box[11];
  p->box2DTextMaxX = box[12];
  p->box2DTextMaxY = box[13];

  for (int j = 0; j < size; j++)
  {
    FaceMap::iterator fi = faces->find(i[j]);
    Face *f = (*fi).second;
    f->set_patch(p);
    p->add_face_patch(f);
  }

  p->index = pc_.size();
  add_patch(p);
  return p;
}

Face* Mesh::add_face(Hedge *e0, Hedge *e1, Hedge *e2)
{
  Face *f = new Face(e0, e1, e2);
  f->index = fc_.size();
  add_face(f);

  return f;
}

Face* Mesh::add_face(Hedge *e0, Hedge *e1, Hedge *e2, float v0, float v1, float v2, float v3, float v4, float v5)
{
  Face *f = new Face(e0, e1, e2, v0, v1, v2, v3, v4, v5);
  f->index = fc_.size();
  add_face(f);

  return f;
}

Hedge* Mesh::add_edge(Vertex *v0, Vertex *v1)
{
  Edge *e = new Edge(v0, v1);
  add_edge(e);
  return e->hedge(0);
}

Vertex* Mesh::add_vertex(void)
{
  Vertex *v = new Vertex();
  add_vertex(v);
  return v;
}

void Mesh::link_mesh()
{
//   for (FaceIter f = fc_.begin(); f != fc_.end(); f++){
//     printf("(%3.3f %3.3f %3.3f) - (%3.3f %3.3f %3.3f) - (%3.3f %3.3f %3.3f)\n", 
//       (*f)->vertex(0)->a.g[X], (*f)->vertex(0)->a.g[Y], (*f)->vertex(0)->a.g[Z],
//       (*f)->vertex(1)->a.g[X], (*f)->vertex(1)->a.g[Y], (*f)->vertex(1)->a.g[Z],
//       (*f)->vertex(2)->a.g[X], (*f)->vertex(2)->a.g[Y], (*f)->vertex(2)->a.g[Z]);
//   }

  for (FaceIter f = fc_.begin(); f != fc_.end(); f++)
    (*f)->link_star_verts();

  for (EdgeIter e = ec_.begin(); e != ec_.end(); e++) {
    Hedge* h = (*e)->hedge(0);
    if (h->is_bdry() && h->face() != NULL)
      h->dst()->set_star(h);
    else if (h->face() == NULL)
      h->org()->set_star(h->mate());
  }
}

Hedge* Mesh::get_hedge(int i0, int i1, Vertex* verts[], HedgeMap *hedges)
{
  bool mate = false;
  if (i0 > i1) {
    std::swap<int>(i0, i1);
    mate = true;
  }
  Hedge* he; HedgeMap::iterator ei  = hedges->find(Ipair(i0,i1));
  if (ei == hedges->end())
    (*hedges)[Ipair(i0,i1)] = he = add_edge(verts[i0], verts[i1]);
  else
    he = (*ei).second;
  return (mate)? he->mate() : he ;
}

void Mesh::put_face(int i0, int i1, int i2, Vertex* verts[], HedgeMap* hedges)
{
  Hedge* e0 = get_hedge(i1, i2, verts, hedges);
  Hedge* e1 = get_hedge(i2, i0, verts, hedges);
  Hedge* e2 = get_hedge(i0, i1, verts, hedges);
  add_face(e0, e1, e2);
}

void Mesh::put_face(int i0, int i1, int i2, float v0, float v1, float v2, float v3, float v4, float v5, Vertex* verts[], HedgeMap* hedges)
{
  Hedge* e0 = get_hedge(i1, i2, verts, hedges);
  Hedge* e1 = get_hedge(i2, i0, verts, hedges);
  Hedge* e2 = get_hedge(i0, i1, verts, hedges);
  add_face(e0, e1, e2, v0, v1, v2, v3, v4, v5);
}

void Mesh::put_face(int i0, int i1, int i2, Vertex* verts[], HedgeMap* hedges, FaceMap* faces)
{
  Hedge* e0 = get_hedge(i1, i2, verts, hedges);
  Hedge* e1 = get_hedge(i2, i0, verts, hedges);
  Hedge* e2 = get_hedge(i0, i1, verts, hedges);

  Face *f = add_face(e0, e1, e2);
  (*faces)[fc_.size() - 1] = f;
}

void Mesh::put_face(int i0, int i1, int i2, float v0, float v1, float v2, float v3, float v4, float v5, Vertex* verts[], HedgeMap* hedges, FaceMap* faces)
{
  Hedge* e0 = get_hedge(i1, i2, verts, hedges);
  Hedge* e1 = get_hedge(i2, i0, verts, hedges);
  Hedge* e2 = get_hedge(i0, i1, verts, hedges);

  Face *f = add_face(e0, e1, e2, v0, v1, v2, v3, v4, v5);
  (*faces)[fc_.size() - 1] = f;
}

void Mesh::remove_patch(Patch *p)
{
  del_patch(p);
}

void Mesh::put_patch()
{
  add_patch();
}

void Mesh::put_patch(int *i, int size, FaceMap* faces, int camera_index, float *box)
{
  add_patch(i, size, faces, camera_index, box);
}

void Mesh::read_ply(char * fname)
{
  ply_read_file(fname, this);
  link_mesh();
}

void Mesh::read_ply_patches(char *fname)
{
  ply_read_patches_file(fname, this);
}
